let drawParams = null; 
let drawCanvas = null; 
let drawContext = null; 
let drawScale = 1; 

let points = []; 
let lastTime = 0; 

export function startWriting(canvas, canvasContext, params, e) { 
  drawParams = params; 
  if(drawParams.scale) drawScale = drawParams.scale;
  drawCanvas = canvas;
  drawContext = canvasContext;
  
  if(drawParams.mode === 'flupen') {
    drawContext.globalCompositeOperation = 'xor';
    drawContext.globalAlpha = 0.5;
  } else {
    drawContext.globalCompositeOperation = 'source-over';
    drawContext.globalAlpha = 1;
  }
  
  const pos = getOffsetPosition(canvas, e, drawScale); 
  points = [ pos ];
  if(drawParams.mode === 'pen' || drawParams.mode === 'flupen') {
    drawContext.beginPath();
    drawContext.moveTo(pos.x, pos.y);
    drawContext.strokeStyle = drawParams.color;
    drawContext.lineWidth = drawParams.size;
  }
}

// skip 跳出记时
export function writingCurve(e, skip=false) { 
  if(!drawCanvas) return;
  const endP = getOffsetPosition(drawCanvas, e, drawScale);  
  const len = points.length;
  const time = new Date().getTime();
  if(skip || time - lastTime >= 20) { 
    if(len >= 2) { 
      const controlP = points[len-1];
      if(len > 2) {
        points = points.splice(len-2, 2);
      } 
      points.push(endP); 
      const midP = getCurveMidPoint(controlP.x, controlP.y, endP.x, endP.y);
      drawContext.quadraticCurveTo(controlP.x, controlP.y, midP.x, midP.y);
      drawContext.stroke();
    } else {
      points.push(endP);
    }
    lastTime = time;
  }
}
export function writingRoundRect(e) {
  if(!drawCanvas) return; 
  const radius = 20 * drawScale; //圆角
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const startP = points[0];
  const len = points.length;
  
  const time = new Date().getTime();
  if(time - lastTime >= 100) {
    if(len >= 2) { 
      drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
    }

    const width = endP.x - startP.x;
    const height = endP.y - startP.y;
    if(width < radius*2 || height < radius*2) return;
    drawContext.beginPath();
    drawContext.strokeStyle = drawParams.color;
    drawContext.lineWidth = drawParams.size;
    drawContext.arc(startP.x+radius, startP.y+radius, radius, Math.PI, 1.5*Math.PI);
    drawContext.lineTo(startP.x+width-radius, startP.y);
    drawContext.arc(startP.x+width-radius, startP.y+radius, radius, 1.5*Math.PI, 2*Math.PI);
    drawContext.lineTo(startP.x+width, startP.y+height-radius);
    drawContext.arc(startP.x+width-radius, startP.y+height-radius, radius, 0, 0.5*Math.PI);
    drawContext.lineTo(startP.x+radius, startP.y+height);
    drawContext.arc(startP.x+radius, startP.y+height-radius, radius, 0.5*Math.PI, Math.PI);
    drawContext.closePath();
    drawContext.stroke();
    drawContext.restore();

    lastTime = time;
    if(len < 2) points.push(endP); 
    else points[1] = endP;
  }
}
export function writingEllipse(e) {
  if(!drawCanvas) return; 
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const startP = points[0];
  const len = points.length;
  
  const time = new Date().getTime();
  if(time - lastTime >= 100) {
    if(len >= 2) { 
      drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
    }

    const width = endP.x - startP.x;
    const height = endP.y - startP.y;
    if(width > 10*drawScale && height > 10*drawScale) {
      drawContext.beginPath();
      drawContext.strokeStyle = drawParams.color;
      drawContext.lineWidth = drawParams.size;
      drawContext.ellipse(startP.x+width/2, startP.y+height/2, width/2, height/2, 0, 0, Math.PI*2)
      drawContext.stroke();
      drawContext.restore();
    }
    lastTime = time;
    if(len < 2) points.push(endP); 
    else points[1] = endP; 
  }
}
export function writingRegtri(e) {
  if(!drawCanvas) return; 
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const startP = points[0];
  const len = points.length;
  
  const time = new Date().getTime();
  if(time - lastTime >= 100) {
    if(len >= 2) { 
      drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
    }

    const width = endP.x - startP.x;
    const height = endP.y - startP.y;
    drawContext.beginPath();
    drawContext.strokeStyle = drawParams.color;
    drawContext.lineWidth = drawParams.size;
    drawContext.moveTo(startP.x+width/2, startP.y);
    drawContext.lineTo(startP.x, startP.y+height);
    drawContext.lineTo(startP.x+width, startP.y+height);
    drawContext.closePath();
    drawContext.stroke();
    drawContext.restore();

    lastTime = time;
    if(len < 2) points.push(endP); 
    else points[1] = endP; 
  }
}
export function writingRighttri(e) {
  if(!drawCanvas) return; 
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const startP = points[0];
  const len = points.length;
  
  const time = new Date().getTime();
  if(time - lastTime >= 100) {
    if(len >= 2) { 
      drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
    }

    const width = endP.x - startP.x;
    const height = endP.y - startP.y;
    drawContext.beginPath();
    drawContext.strokeStyle = drawParams.color;
    drawContext.lineWidth = drawParams.size;
    drawContext.moveTo(startP.x, startP.y);
    drawContext.lineTo(startP.x, startP.y+height);
    drawContext.lineTo(startP.x+width, startP.y+height);
    drawContext.closePath();
    drawContext.stroke();
    drawContext.restore();

    lastTime = time;
    if(len < 2) points.push(endP); 
    else points[1] = endP; 
  }
}
export function writingArrowRight(e) {
  if(!drawCanvas) return; 
  const endP = getOffsetPosition(drawCanvas, e, drawScale);
  const startP = points[0];
  const len = points.length;
  
  const time = new Date().getTime();
  if(time - lastTime >= 100) {
    if(len >= 2) { 
      drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
    }
    const arrowLen = 20 * drawScale;
    const width = endP.x - startP.x;
    const height = endP.y - startP.y;
    if(Math.abs(width) < arrowLen && Math.abs(height) < arrowLen) return;
    let angleA = Math.round(Math.atan2(height, width) * 180 / Math.PI); 

    const angle = 30;
    const hu1 = (angle + angleA) * Math.PI / 180
    const ah1 = Math.sin(hu1) * arrowLen;
    const aw1 = Math.cos(hu1) * arrowLen;

    const hu2 = (angle - angleA) * Math.PI / 180
    const ah2 = Math.sin(hu2) * arrowLen;
    const aw2 = Math.cos(hu2) * arrowLen;

    drawContext.beginPath();
    drawContext.strokeStyle = drawParams.color;
    drawContext.lineWidth = drawParams.size;
    drawContext.moveTo(startP.x, startP.y);
    drawContext.lineTo(endP.x, endP.y);
    drawContext.lineTo(endP.x - aw1, endP.y - ah1); 
    drawContext.moveTo(endP.x, endP.y);
    drawContext.lineTo(endP.x - aw2, endP.y + ah2);

    drawContext.stroke();
    drawContext.restore();

    lastTime = time;
    if(len < 2) points.push(endP); 
    else points[1] = endP; 
  }
}

export function stopWriting(e) { 
  if(!e) {
    return getWritingRecord();
  }
  if(drawContext) drawContext.restore();
  const record = getWritingRecord();

  drawCanvas = null;
  drawContext = null;
  drawParams = null;

  points = []; 
  lastTime = 0;

  return record;
}

export function erase(canvas, context, params, e) {
  const point = getOffsetPosition(canvas, e, params.scale);
  context.save();
  context.beginPath();
  context.arc(point.x, point.y, params.size*params.scale/2, 0, 2*Math.PI);
  context.clip();
  context.clearRect(0, 0, params.width, params.height);
  context.restore();
  points.push({ x: point.x, y: point.y });
}

export function clear(context, params) {
  context.clearRect(0, 0, params.width, params.height);
}

function getWritingRecord() {
  if(!drawParams) return null;
  const record = drawParams;
  record.points = points;
  return record;
}

export function getOffsetPosition(canvas, e, scale) { 
  const event = e instanceof MouseEvent ? e : e.changedTouches[0];
  // console.log('e', event.pageX, event.pageY)
  const canvasRect = canvas.getBoundingClientRect(); 
  const x = event.pageX - canvasRect.x;
  const y = event.pageY - canvasRect.y;
  return { x: Math.round(x*scale), y: Math.round(y*scale) }
}
function getCurveMidPoint(x1, y1, x2, y2) {
  const x = (x1 + x2) / 2;
  const y = (y1 + y2) / 2;
  return { x, y };
} 

export function drawShape(context, ele) {
  context.globalCompositeOperation = 'source-over';
  context.globalAlpha = 1;
  switch(ele.mode) {
    case 'arrowright': 
      drawArrowRight(context, ele);
      break;
    case 'roundrect':
      drawRoundRect(context, ele);
      break;
    case 'ellipse':
      drawEllipse(context, ele);
      break;
    case 'regtri':
      drawRegtri(context, ele);
      break;
    case 'righttri':
      drawRighttri(context, ele);
      break;
  }
}

function drawRighttri(context, ele) {
  if(ele.points.length < 2) return;
  const startP = ele.points[0];
  const endP = ele.points[1];
  const width = endP.x - startP.x;
  const height = endP.y - startP.y;
  context.beginPath();
  context.strokeStyle = ele.color;
  context.lineWidth = ele.size;
  context.moveTo(startP.x, startP.y);
  context.lineTo(startP.x, startP.y+height);
  context.lineTo(startP.x+width, startP.y+height);
  context.closePath();
  context.stroke();
  context.restore();
}
function drawRoundRect(context, ele) { 
  const radius = 20 * ele.scale; //圆角
  if(ele.points.length < 2) return;
  const startP = ele.points[0];
  const endP = ele.points[1];
  const width = endP.x - startP.x;
  const height = endP.y - startP.y;
  context.beginPath();
  context.strokeStyle = ele.color;
  context.lineWidth = ele.size;
  context.arc(startP.x+radius, startP.y+radius, radius, Math.PI, 1.5*Math.PI);
  context.lineTo(startP.x+width-radius, startP.y);
  context.arc(startP.x+width-radius, startP.y+radius, radius, 1.5*Math.PI, 2*Math.PI);
  context.lineTo(startP.x+width, startP.y+height-radius);
  context.arc(startP.x+width-radius, startP.y+height-radius, radius, 0, 0.5*Math.PI);
  context.lineTo(startP.x+radius, startP.y+height);
  context.arc(startP.x+radius, startP.y+height-radius, radius, 0.5*Math.PI, Math.PI);
  context.closePath();
  context.stroke();
  context.restore();
}
function drawRegtri(context, ele) {
  if(ele.points.length < 2) return;
  const startP = ele.points[0];
  const endP = ele.points[1];
  const width = endP.x - startP.x;
  const height = endP.y - startP.y;
  context.beginPath();
  context.strokeStyle = ele.color;
  context.lineWidth = ele.size;
  context.moveTo(startP.x+width/2, startP.y);
  context.lineTo(startP.x, startP.y+height);
  context.lineTo(startP.x+width, startP.y+height);
  context.closePath();
  context.stroke();
  context.restore();
}
function drawEllipse(context, ele) {
  if(ele.points.length < 2) return;
  const startP = ele.points[0];
  const endP = ele.points[1];
  const width = endP.x - startP.x;
  const height = endP.y - startP.y;
  context.beginPath();
  context.strokeStyle = ele.color;
  context.lineWidth = ele.size;
  context.ellipse(startP.x+width/2, startP.y+height/2, width/2, height/2, 0, 0, Math.PI*2)
  context.stroke();
  context.restore();
}
function drawArrowRight(context, ele) {
  if(ele.points.length < 2) return;
  const startP = ele.points[0];
  const endP = ele.points[1];
  const width = endP.x - startP.x;
  const height = endP.y - startP.y;

  const arrowLen = 20 * ele.scale; //箭头长度
  const angle = 30; // 箭头夹角
  //线在屏幕中的坐标夹角
  let angleA = Math.round(Math.atan2(height, width) * 180 / Math.PI); 
  // 上半箭头的坐标
  const hu1 = (angle + angleA) * Math.PI / 180
  const ah1 = Math.sin(hu1) * arrowLen;
  const aw1 = Math.cos(hu1) * arrowLen;
  // 下半箭头的坐标
  const hu2 = (angle - angleA) * Math.PI / 180
  const ah2 = Math.sin(hu2) * arrowLen;
  const aw2 = Math.cos(hu2) * arrowLen;

  context.beginPath();
  context.strokeStyle = ele.color;
  context.lineWidth = ele.size;
  context.moveTo(startP.x, startP.y);
  context.lineTo(endP.x, endP.y);
  context.lineTo(endP.x - aw1, endP.y - ah1); 
  context.moveTo(endP.x, endP.y);
  context.lineTo(endP.x - aw2, endP.y + ah2);

  context.stroke();
  context.restore();
}
